﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Un4seen.Bass;
using Un4seen.Bass.Misc;
using Un4seen.Bass.AddOn.Fx;

namespace EditorDeAudioTT201095
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private int flujo = 0;
        private int flujoEfectos = 0;
        private string nombreDeArchivo = String.Empty;
        private int latenciaDispositivoEnMilisegundos = 0;
        private int latenciaDispositivoEnBytes = 0;
        private DSP_PeakLevelMeter medidorNivelCimas;
        private DSP_Gain ganancia;
        private BASS_INFO informacion = Bass.BASS_GetInfo();
        private Un4seen.Bass.BASSTimer actualizarContadorTiempo = null;
        private BASS_DX8_COMPRESSOR compresor = new BASS_DX8_COMPRESSOR();
        private BASS_BFX_DAMP moderador = new BASS_BFX_DAMP();
        private int prioridadModerador = 9;
        private int intervaloActualizacion = 50; // Medido en milisegundos
        private int contadorInstante = 0;
        private int sincronia = 0;
        private SYNCPROC sincronizador = null;
        private Visuals modificadorVisual = new Visuals();
        private bool espectroCompleto = true;
        private int[] equalizador = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        private int longitud = 0;

        private void buttonSeleccionArchivo_Click(object sender, EventArgs e)
        {
            openFileDialogAbrir.FileName = nombreDeArchivo;
            if (DialogResult.OK == this.openFileDialogAbrir.ShowDialog(this))
            {
                if (File.Exists(this.openFileDialogAbrir.FileName))
                {
                    nombreDeArchivo = this.openFileDialogAbrir.FileName;
                    this.buttonSeleccionArchivo.Text = Path.GetFileName(nombreDeArchivo);
                }
                else
                    nombreDeArchivo = String.Empty;
            }
        }

        private void buttonReproducir_Click(object sender, EventArgs e)
        {
            actualizarContadorTiempo.Stop();
            Bass.BASS_StreamFree(flujo);
            if (nombreDeArchivo != String.Empty)
            {
                // Crea el flujo
                flujo = Bass.BASS_StreamCreateFile(nombreDeArchivo, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_SPEAKER_FRONT);
                if (flujo != 0)
                {
                    // Latencia del dispositivo de milisegundos a bytes
                    latenciaDispositivoEnBytes = (int)Bass.BASS_ChannelSeconds2Bytes(flujo, latenciaDispositivoEnMilisegundos / 1000f);

                    if (medidorNivelCimas != null)
                        medidorNivelCimas.Notification -= new EventHandler(Notificacion_MedidorNivelCimas);

                    medidorNivelCimas = new DSP_PeakLevelMeter(flujo, 2000);
                    medidorNivelCimas.CalcRMS = true;
                    medidorNivelCimas.Notification += new EventHandler(Notificacion_MedidorNivelCimas);

                    ganancia = new DSP_Gain(flujo, 0);
                    buttonEstablecerGanancia_Click(this, EventArgs.Empty);
                    trackBarGanancia_ValueChanged_1(this, EventArgs.Empty);

                    // EQ de 10 bandas
                    BASS_DX8_PARAMEQ eq = new BASS_DX8_PARAMEQ();
                    equalizador[0] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[1] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[2] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[3] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[4] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[5] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[6] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[7] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[8] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    equalizador[9] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);

                    eq.fBandwidth = 18f;

                    eq.fCenter = 31f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[0], eq);

                    eq.fCenter = 63f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[1], eq);

                    eq.fCenter = 125f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[2], eq);

                    eq.fCenter = 250f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[3], eq);

                    eq.fCenter = 500f;
                    eq.fGain = this.trackBarEQBanda63.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[4], eq);

                    eq.fCenter = 1000f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[5], eq);

                    eq.fCenter = 2000f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[6], eq);

                    eq.fCenter = 4000f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[7], eq);

                    eq.fCenter = 8000f;
                    eq.fGain = this.trackBarEQBanda125.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[8], eq);

                    eq.fCenter = 16000f;
                    eq.fGain = this.trackBarEQBanda125.Value / 10f;
                    Bass.BASS_FXSetParameters(equalizador[9], eq);

                        longitud = (int)Bass.BASS_ChannelSeconds2Bytes(flujo, 0.02f); // Ventana de 20ms
                        bpmProc = new BPMPROCESSPROC(MyBPMProc);
                        float bpm = BassFx.BASS_FX_BPM_DecodeGet(flujo, 1f, 180f, Utils.MakeLong(50, 180), BASSFXBpm.BASS_FX_BPM_BKGRND | BASSFXBpm.BASS_FX_FREESOURCE | BASSFXBpm.BASS_FX_BPM_MULT2, bpmProc);
                        this.labelBPM.Text = String.Format("BPM={0}", bpm);
                        
                        Bass.BASS_ChannelSetPosition(flujo, 0);

                        flujoEfectos = BassFx.BASS_FX_TempoCreate(flujo, BASSFlag.BASS_FX_FREESOURCE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_SAMPLE_LOOP);
                    
                    if (flujoEfectos != 0 && Bass.BASS_ChannelPlay(flujoEfectos, false))
                    {
                        this.actualizarContador.Start();

                        // real-time beat position
                        beatProc = new BPMBEATPROC(MyBeatProc);
                        BassFx.BASS_FX_BPM_BeatCallbackSet(flujoEfectos, beatProc, IntPtr.Zero);
                    }
                    else
                    {
                        Console.WriteLine("Error = {0}", Bass.BASS_ErrorGetCode());
                    }
                }

                if (flujo != 0 && Bass.BASS_ChannelPlay(flujo, false))
                {
                    // Dibuja la señal, se realiza en un thread en segundo plano para realizar la reproducción el paralelo
          
                    GetWaveForm();

                    Console.WriteLine("Reproduciendo");

                    actualizarContadorTiempo.Start();

                    this.buttonDetener.Enabled = true;
                    this.buttonReproducir.Enabled = false;
                }
                else
                {
                    Console.WriteLine("Error = {0}", Bass.BASS_ErrorGetCode());
                }
            }
        }

        private void Notificacion_MedidorNivelCimas(object sender, EventArgs e)
        {
            try
            {
                this.progressBarCimaIzquierda.Value = medidorNivelCimas.LevelL;
                this.progressBarCimaDerecha.Value = medidorNivelCimas.LevelR;
                this.labelLevelInformacion.Text = String.Format("RMS: {0:#00.0} dB    Promedio: {1:#00.0} dB    Cima: {2:#00.0} dB", medidorNivelCimas.RMS_dBV, medidorNivelCimas.AVG_dBV, Math.Max(medidorNivelCimas.PeakHoldLevelL_dBV, medidorNivelCimas.PeakHoldLevelR_dBV));
            }
            catch { }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_LATENCY, this.Handle))
            {
                informacion = Bass.BASS_GetInfo();
                latenciaDispositivoEnMilisegundos = informacion.latency;
            }
            else
                MessageBox.Show(this, "¡Error al inicializar dispositivo!");

            BassFx.BASS_FX_GetVersion();

            // Inicializar efectos
            compresor.Preset_Soft();
            moderador.Preset_Medium();

            // create a secure timer
            actualizarContadorTiempo = new Un4seen.Bass.BASSTimer(intervaloActualizacion);
            actualizarContadorTiempo.Tick += new EventHandler(ActualizarInstanteContador);

            sincronizador = new SYNCPROC(SetPosition);

            modificadorVisual.MaxFFT = BASSData.BASS_DATA_FFT1024;
            modificadorVisual.MaxFrequencySpectrum = Utils.FFTFrequency2Index(16000, 1024, 44100);
        }

        private void buttonEstablecerGanancia_Click(object sender, EventArgs e)
        {
            if (ganancia != null)
            {
                try
                {
                    double gainDB = double.Parse(this.textBoxValorGananciadB.Text);
                    if (gainDB == 0.0)
                        ganancia.SetBypass(true);
                    else
                    {
                        ganancia.SetBypass(false);
                        ganancia.Gain_dBV = gainDB;
                    }
                    trackBarGanancia.Value = (int)(gainDB * 1000d);
                }
                catch { }
            }
        }

        private void buttonPausar_Click(object sender, EventArgs e)
        {
            if (Bass.BASS_ChannelIsActive(flujo) == BASSActive.BASS_ACTIVE_PLAYING)
            {
                Bass.BASS_ChannelPause(flujo);
            }
            else
            {
                Bass.BASS_ChannelPlay(flujo, false);
            }
        }

        private void buttonDetener_Click(object sender, EventArgs e)
        {
            DetenerFlujo();
        }

        private void DetenerFlujo()
        {
            actualizarContadorTiempo.Stop();
            if (WF != null && WF.IsRenderingInProgress)
                WF.RenderStop();
            DrawWavePosition(-1, -1);

            Bass.BASS_StreamFree(flujo);
            flujo = 0;
            this.labelContador.Text = "Detenido";
            this.buttonSeleccionArchivo.Text = "Abrir";
            this.buttonDetener.Enabled = false;
            this.buttonReproducir.Enabled = true;
        }

        #region Wave Form

        // zoom helper varibales
        private bool _zoomed = false;
        private int _zoomStart = -1;
        private long _zoomStartBytes = -1;
        private int _zoomEnd = -1;
        private float _zoomDistance = 5.0f; // zoom = 5sec.

        private Un4seen.Bass.Misc.WaveForm WF = null;
        private void GetWaveForm()
        {
            WF = new WaveForm(this.nombreDeArchivo, new WAVEFORMPROC(MyWaveFormCallback), this);
            WF.FrameResolution = 0.005f; // 5ms are very nice
            WF.CallbackFrequency = 4000; // every 20 seconds rendered (4000*5ms=20sec)
            WF.ColorBackground = SystemColors.Control;
            WF.ColorLeft = Color.Gainsboro;
            WF.ColorLeftEnvelope = Color.Gray;
            WF.ColorRight = Color.LightGray;
            WF.ColorRightEnvelope = Color.DimGray;
            WF.ColorMarker = Color.DarkBlue;
            WF.DrawWaveForm = WaveForm.WAVEFORMDRAWTYPE.Stereo;
            WF.DrawMarker = WaveForm.MARKERDRAWTYPE.Line | WaveForm.MARKERDRAWTYPE.Name | WaveForm.MARKERDRAWTYPE.NamePositionAlternate;
            WF.RenderStart(true, BASSFlag.BASS_DEFAULT);
            WF.SyncPlayback(flujo);
        }

        private void MyWaveFormCallback(int framesDone, int framesTotal, TimeSpan elapsedTime, bool finished)
        {
            // will be called during rendering...
            DrawWave();
            if (finished)
            {
                Console.WriteLine("Finished rendering in {0}sec.", elapsedTime);
                Console.WriteLine("FramesRendered={0} of {1}", WF.FramesRendered, WF.FramesToRender);
            }
        }

        private void pictureBox1_Resize(object sender, System.EventArgs e)
        {
            DrawWave();
        }

        private void DrawWave()
        {
            if (WF != null)
                this.pictureBoxGrafica.BackgroundImage = WF.CreateBitmap(this.pictureBoxGrafica.Width, this.pictureBoxGrafica.Height, _zoomStart, _zoomEnd, true);
            else
                this.pictureBoxGrafica.BackgroundImage = null;
        }

        private void DrawWavePosition(long pos, long len)
        {
            if (len == 0 || pos < 0)
            {
                this.pictureBoxGrafica.Image = null;
                return;
            }

            Bitmap bitmap = null;
            Graphics g = null;
            Pen p = null;
            double bpp = 0;

            try
            {
                if (_zoomed)
                {
                    // total length doesn't have to be _zoomDistance sec. here
                    len = WF.Frame2Bytes(_zoomEnd) - _zoomStartBytes;

                    int scrollOffset = 1;
                    // if we scroll out the window...(scrollOffset*20ms before the zoom window ends)
                    if (pos > (_zoomStartBytes + len - scrollOffset * WF.Wave.bpf))
                    {
                        // we 'scroll' our zoom with a little offset
                        _zoomStart = WF.Position2Frames(pos - scrollOffset * WF.Wave.bpf);
                        _zoomStartBytes = WF.Frame2Bytes(_zoomStart);
                        _zoomEnd = _zoomStart + WF.Position2Frames(_zoomDistance) - 1;
                        if (_zoomEnd >= WF.Wave.data.Length)
                        {
                            // beyond the end, so we zoom from end - _zoomDistance.
                            _zoomEnd = WF.Wave.data.Length - 1;
                            _zoomStart = _zoomEnd - WF.Position2Frames(_zoomDistance) + 1;
                            if (_zoomStart < 0)
                                _zoomStart = 0;
                            _zoomStartBytes = WF.Frame2Bytes(_zoomStart);
                            // total length doesn't have to be _zoomDistance sec. here
                            len = WF.Frame2Bytes(_zoomEnd) - _zoomStartBytes;
                        }
                        // get the new wave image for the new zoom window
                        DrawWave();
                    }
                    // zoomed: starts with _zoomStartBytes and is _zoomDistance long
                    pos -= _zoomStartBytes; // offset of the zoomed window

                    bpp = len / (double)this.pictureBoxGrafica.Width;  // bytes per pixel
                }
                else
                {
                    // not zoomed: width = length of stream
                    bpp = len / (double)this.pictureBoxGrafica.Width;  // bytes per pixel
                }

                pos -= latenciaDispositivoEnBytes;

                p = new Pen(Color.Red);
                bitmap = new Bitmap(this.pictureBoxGrafica.Width, this.pictureBoxGrafica.Height);
                g = Graphics.FromImage(bitmap);
                g.Clear(Color.White);
                int x = (int)Math.Round(pos / bpp);  
                g.DrawLine(p, x, 0, x, this.pictureBoxGrafica.Height - 1);
                bitmap.MakeTransparent(Color.White);
            }
            catch
            {
                bitmap = null;
            }
            finally
            {
                // clean up graphics resources
                if (p != null)
                    p.Dispose();
                if (g != null)
                    g.Dispose();
            }

            this.pictureBoxGrafica.Image = bitmap;
        }

        private void buttonZoom_Click(object sender, System.EventArgs e)
        {
            if (WF == null)
                return;

            // WF is not null, so the stream must be playing...
            if (_zoomed)
            {
                // unzoom...(display the whole wave form)
                _zoomStart = -1;
                _zoomStartBytes = -1;
                _zoomEnd = -1;
                _zoomDistance = 5.0f; // zoom = 5sec.
            }
            else
            {
                // zoom...(display only a partial wave form)
                long pos = Bass.BASS_ChannelGetPosition(this.flujo);
                // calculate the window to display
                _zoomStart = WF.Position2Frames(pos);
                _zoomStartBytes = WF.Frame2Bytes(_zoomStart);
                _zoomEnd = _zoomStart + WF.Position2Frames(_zoomDistance) - 1;
                if (_zoomEnd >= WF.Wave.data.Length)
                {
                    // beyond the end, so we zoom from end - _zoomDistance.
                    _zoomEnd = WF.Wave.data.Length - 1;
                    _zoomStart = _zoomEnd - WF.Position2Frames(_zoomDistance) + 1;
                    _zoomStartBytes = WF.Frame2Bytes(_zoomStart);
                }
            }
            _zoomed = !_zoomed;
            // and display this new wave form
            DrawWave();
        }

        private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (WF == null)
                return;

            if (e.Button == MouseButtons.Left)
            {
                long pos = WF.GetBytePositionFromX(e.X, this.pictureBoxGrafica.Width, _zoomStart, _zoomEnd);
                // set Start marker
                WF.AddMarker("INICIO", pos);
                Bass.BASS_ChannelSetPosition(flujo, pos);
                if (WF.Wave.marker.ContainsKey("FIN"))
                {
                    long endpos = WF.Wave.marker["FIN"];
                    if (endpos < pos)
                    {
                        WF.RemoveMarker("FIN");
                    }
                }
                DrawWave();
            }
            else if (e.Button == MouseButtons.Right)
            {
                long pos = WF.GetBytePositionFromX(e.X, this.pictureBoxGrafica.Width, _zoomStart, _zoomEnd);
                // set End marker
                WF.AddMarker("FIN", pos);
                Bass.BASS_ChannelRemoveSync(flujo, sincronia);
                sincronia = Bass.BASS_ChannelSetSync(flujo, BASSSync.BASS_SYNC_POS, pos, sincronizador, IntPtr.Zero);
                if (WF.Wave.marker.ContainsKey("INICIO"))
                {
                    long startpos = WF.Wave.marker["INICIO"];
                    if (startpos > pos)
                    {
                        WF.RemoveMarker("INICIO");
                    }
                }
                DrawWave();
            }
        }

        private void SetPosition(int handle, int channel, int data, IntPtr user)
        {
            if (WF.Wave.marker.ContainsKey("INICIO"))
            {
                long startpos = WF.Wave.marker["INICIO"];
                Bass.BASS_ChannelSetPosition(flujo, (long)startpos);
                if (_zoomed)
                {
                    _zoomStart = WF.Position2Frames((long)startpos) - 1;
                    _zoomStartBytes = WF.Frame2Bytes(_zoomStart);
                    if (WF.Wave.marker.ContainsKey("FIN"))
                    {
                        long endpos = WF.Wave.marker["FIN"];
                        _zoomEnd = WF.Position2Frames((long)endpos) + 10;
                        _zoomDistance = WF.Frame2Bytes(_zoomEnd) - WF.Frame2Bytes(_zoomStart);
                    }
                    DrawWave();
                }
            }
            else
                Bass.BASS_ChannelSetPosition(flujo, 0);

        }

        #endregion

        private void ActualizarInstanteContador(object sender, System.EventArgs e)
        {
            if (Bass.BASS_ChannelIsActive(flujo) == BASSActive.BASS_ACTIVE_STOPPED)
                return;
            
            contadorInstante++;
            long pos = Bass.BASS_ChannelGetPosition(flujo); // position in bytes
            long len = Bass.BASS_ChannelGetLength(flujo); // length in bytes

            if (contadorInstante == 20)
            {
                contadorInstante = 0;
                // reset the peak level every 1000ms (since timer is 50ms)
                if (medidorNivelCimas != null)
                    medidorNivelCimas.ResetPeakHold();
            }
            if (contadorInstante % 5 == 0)
            {
                // display the position every 250ms (since timer is 50ms)
                double totaltime = Bass.BASS_ChannelBytes2Seconds(flujo, len); // the total time length
                double elapsedtime = Bass.BASS_ChannelBytes2Seconds(flujo, pos); // the elapsed time length
                double remainingtime = totaltime - elapsedtime;
                this.labelContador.Text = String.Format("Transcurrido: {0:#0.00} - Duración: {1:#0.00} - Restante: {2:#0.00}", Utils.FixTimespan(elapsedtime, "MMSS"), Utils.FixTimespan(totaltime, "MMSS"), Utils.FixTimespan(remainingtime, "MMSS"));
                this.Text = String.Format("CPU: {0:0.00}%", Bass.BASS_GetCPU());
            }

            // update the wave position
            DrawWavePosition(pos, len);
            if (espectroCompleto)
                this.pictureBoxEspectro.Image = modificadorVisual.CreateSpectrumLinePeak(flujo, this.pictureBoxEspectro.Width, this.pictureBoxEspectro.Height, Color.LightBlue, Color.Blue, Color.Aqua, Color.Black, 2, 1, 1, 13, false, true, false);
            else
                this.pictureBoxEspectro.Image = modificadorVisual.CreateWaveForm(flujo, this.pictureBoxEspectro.Width, this.pictureBoxEspectro.Height, Color.Aqua, Color.Red, Color.Gray, Color.Linen, 1, true, false, true);
        }

        private void pictureBoxEspectro_Click(object sender, EventArgs e)
        {
            espectroCompleto = !espectroCompleto;
        }

        #region DynAmp

        private int _dampFX = 0;

        private void checkBoxAmplifDinamica_CheckedChanged(object sender, EventArgs e)
        {
            if (flujo == 0)
                return;

            if (checkBoxAmplifDinamica.Checked)
            {
                _dampFX = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_BFX_DAMP, prioridadModerador);
                Bass.BASS_FXSetParameters(_dampFX, moderador);

            }
            else
            {
                Bass.BASS_ChannelRemoveFX(flujo, _dampFX);
                _dampFX = 0;
            }
        }

        #endregion DynAmp

        private void trackBarGanancia_ValueChanged_1(object sender, EventArgs e)
        {
            if (ganancia != null)
                this.textBoxValorGananciadB.Text = Convert.ToString(trackBarGanancia.Value / 1000d);
            buttonEstablecerGanancia_Click(this, EventArgs.Empty);
        }

        private void UpdateEQ(int band, float gain)
        {
            BASS_DX8_PARAMEQ eq = new BASS_DX8_PARAMEQ();
            if (Bass.BASS_FXGetParameters(equalizador[band], eq))
            {
                eq.fGain = gain;
                Bass.BASS_FXSetParameters(equalizador[band], eq);
            }
        }

        private void trackBarEQBanda31_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(0, trackBarEQBanda31.Value / 10f);
        }

        private void trackBarEQBanda63_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(1, trackBarEQBanda63.Value / 10f);
        }

        private void trackBarEQBanda125_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(2, trackBarEQBanda125.Value / 10f);
        }

        private void trackBarEQBanda250_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(3, trackBarEQBanda250.Value / 10f);
        }

        private void trackBarEQBanda500_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(4, trackBarEQBanda500.Value / 10f);
        }

        private void trackBarEQBanda1000_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(5, trackBarEQBanda1000.Value / 10f);
        }

        private void trackBarEQBanda2000_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(6, trackBarEQBanda2000.Value / 10f);
        }

        private void trackBarEQBanda4000_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(7, trackBarEQBanda4000.Value / 10f);
        }

        private void trackBarEQBanda8000_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(8, trackBarEQBanda8000.Value / 10f);
        }

        private void trackBarEQBanda16000_ValueChanged(object sender, EventArgs e)
        {
            UpdateEQ(9, trackBarEQBanda16000.Value / 10f);
        }

        private int _flangerFX = 0;
        private void checkBoxFlanger_CheckedChanged(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            if (this.checkBoxFlanger.Checked)
            {
                // and add a DSP here as well...
                _flangerFX = Bass.BASS_ChannelSetFX(flujoEfectos, BASSFXType.BASS_FX_BFX_FLANGER, -4);
                BASS_BFX_FLANGER flanger = new BASS_BFX_FLANGER();
                flanger.Preset_Default();
                Bass.BASS_FXSetParameters(_flangerFX, flanger);

                // just to demo how to get
                BASS_BFX_FLANGER f = new BASS_BFX_FLANGER();
                Bass.BASS_FXGetParameters(_flangerFX, f);
            }
            else
            {
                // remove the DSP
                Bass.BASS_ChannelRemoveFX(flujoEfectos, _flangerFX);
                _flangerFX = 0;
            }
        }

        private void buttonFlangerApply_Click(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            BASS_BFX_FLANGER flanger = new BASS_BFX_FLANGER();
            
            Bass.BASS_FXGetParameters(_flangerFX, flanger);
            flanger.fSpeed = float.Parse(this.textBoxFlangerSpeed.Text);
            
            Bass.BASS_FXSetParameters(_flangerFX, flanger);
        }

        private int _echoFX = 0;
        private void checkBoxEcho_CheckedChanged(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            if (this.checkBoxEcho.Checked)
            {
                // Modificar el DSP
                _echoFX = Bass.BASS_ChannelSetFX(flujoEfectos, BASSFXType.BASS_FX_BFX_ECHO3, -3);
                BASS_BFX_ECHO3 echo = new BASS_BFX_ECHO3();
                echo.Preset_LongEcho();
                Bass.BASS_FXSetParameters(_echoFX, echo);
            }
            else
            {
                // Remueve el DSP
                Bass.BASS_ChannelRemoveFX(flujoEfectos, _echoFX);
                _echoFX = 0;
            }
        }

        private void buttonEchoApply_Click(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            BASS_BFX_ECHO3 echo = new BASS_BFX_ECHO3();
            
            Bass.BASS_FXGetParameters(_echoFX, echo);
            echo.fDelay = float.Parse(this.textBoxEchoDelay.Text);
            
            Bass.BASS_FXSetParameters(_echoFX, echo);
        }

        private int efectoReverb = 0;
        private void checkBoxReverb_CheckedChanged(object sender, EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            if (this.checkBoxReverb.Checked)
            {
                efectoReverb = Bass.BASS_ChannelSetFX(flujoEfectos, BASSFXType.BASS_FX_BFX_REVERB, -3);
                BASS_BFX_REVERB reverb = new BASS_BFX_REVERB();
                reverb.fLevel = 0.5f;
                Bass.BASS_FXSetParameters(efectoReverb, reverb);
            }
            else
            {
                // Remueve el DSP
                Bass.BASS_ChannelRemoveFX(flujoEfectos, efectoReverb);
                efectoReverb = 0;
            }
        }

        private BPMPROCESSPROC bpmProc;
        private void MyBPMProc(int chan, float percent)
        {
            BeginInvoke((MethodInvoker)delegate()
            {
                this.labelBPM.Text = String.Format("{0}%", percent);
            });
        }

        private BPMBEATPROC beatProc;
        private void MyBeatProc(int handle, double beatpos, IntPtr user)
        {
            BeginInvoke((MethodInvoker)delegate()
            {
                // this code runs on the UI thread!
                this.labelBPM.BackColor = Color.Red;
            });
        }

        private void buttonAplicarReverb_Click(object sender, EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            BASS_BFX_REVERB reverb = new BASS_BFX_REVERB();
            
            Bass.BASS_FXGetParameters(efectoReverb, reverb);
            reverb.lDelay = int.Parse(this.textBoxRetrasoReverb.Text);
            
            Bass.BASS_FXSetParameters(efectoReverb, reverb);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Microfono manejoMicrofono = new Microfono();
            this.Hide();
            manejoMicrofono.ShowDialog();
        }
    }
}
